package com.example.batch.config;

import com.example.batch.entity.Person;
import com.example.batch.listen.JobCompletionNotificationListener;
import com.example.batch.listen.read.PersonItemReadListener;
import com.example.batch.listen.write.PersonItemWriteListener;
import com.example.batch.processor.PersonItemProcessor;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.MappingJsonFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.item.database.JpaItemWriter;
import org.springframework.batch.item.database.builder.JpaItemWriterBuilder;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.LineMapper;
import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
import org.springframework.batch.item.file.mapping.FieldSetMapper;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;

import javax.persistence.EntityManagerFactory;
import java.io.IOException;

@Slf4j
public class PersonMigrationJobConfiguration {
    @Autowired
    private JobBuilderFactory jobBuilderFactory;
    @Autowired
    private StepBuilderFactory stepBuilderFactory;
    @Autowired
    private EntityManagerFactory entityManagerFactory;

    @Bean
    public Job personMigrationJob(@Qualifier("jobListen")JobCompletionNotificationListener listener,@Qualifier("personMigrationStep") Step personMigrationStep) {
        return jobBuilderFactory.get("personMigrationJob")
                .incrementer(new RunIdIncrementer())
                .listener(listener)
                .flow(personMigrationStep)
                .end()
                .build();
    }

    @Bean
    public Step personMigrationStep(@Qualifier("personItemReader") FlatFileItemReader<Person> personFlatFileItemReader,
                                    @Qualifier("personItemWriter") JpaItemWriter<Person> personItemWriter) {
        return stepBuilderFactory.get("personMigrationStep")
                .<Person, Person>chunk(10)
                .reader(personFlatFileItemReader).faultTolerant().skip(JsonParseException.class).skipLimit(20)
                .listener(new PersonItemReadListener())
                .processor(processor())
                .writer(personItemWriter).faultTolerant().skip(Exception.class).skipLimit(20)
                .listener(new PersonItemWriteListener())
                .build();
    }

    @Bean
    public FlatFileItemReader<Person> personItemReader() {
        return new FlatFileItemReaderBuilder<Person>()
                .name("personItemReader")
                .linesToSkip(1)
                .resource(new ClassPathResource("template/sample-data.csv"))
                .delimited().names(new String[]{"firstName", "lastName"})
                .fieldSetMapper(new BeanWrapperFieldSetMapper<Person>() {{
                    setTargetType(Person.class);
                }})
//                .fieldSetMapper(new PersonMapper())
//                .lineTokenizer(new DelimitedLineTokenizer())
                .build();
    }

    public class PersonMapper implements FieldSetMapper<Person> {
        public Person mapFieldSet(FieldSet fs) {
            return new Person(fs.readString(0), fs.readString(1));
        }
    }

    public class PersonLineMapper implements LineMapper<Person> {
        private MappingJsonFactory factory = new MappingJsonFactory();

        @Override
        public Person mapLine(String line, int lineNumber) {
            Person person = new Person();
            try {
                JsonParser parser = factory.createParser(line);
//                log.info(map.toString());
            } catch (IOException e) {
                e.printStackTrace();
            }
            return person;
        }
    }

    @Bean
    public JpaItemWriter<Person> personItemWriter() {
        return new JpaItemWriterBuilder<Person>()
                .entityManagerFactory(entityManagerFactory)
                .build();
    }

    @Bean
    public PersonItemProcessor processor() {
        return new PersonItemProcessor();
    }
}
